package navigation;

import config.*;

/**
 *
 * @author hyurah
 */

public class Map {
	
	private int xSize;
	private int ySize;
	private Field[][] map;
	private boolean startKnown = false;
	private boolean measuresKnown = false;
	private int redX = -1;
	private int redY = -1;

	public Map() {
		if(Config.STARTATNARROWSIDE) {
			xSize=Config.MINFIELDS;
			ySize=Config.MAXFIELDS;
			measuresKnown=true;
		} else {
			xSize=Config.MAXFIELDS;
			ySize=Config.MAXFIELDS;
			if(Config.MAXFIELDS==Config.MINFIELDS) {
				measuresKnown = true;
			}
		}
		map=new Field[xSize][ySize];
		for(int i=0; i<xSize; i++) {
			map[i]=new Field[ySize];
			for(int j=0; j<ySize; j++) {
				map[i][j]= new Field();
			}
		}
	}

	public void startKnown(int startSide) {
		lookForExits(startSide);
		startKnown = true;
	}

	public boolean measuresKnown() {
		return measuresKnown;
	}

	public boolean fieldIsKnown(int x, int y) {
		return map[x][y].isKnown();
	}

	public boolean fieldIsExit(int x, int y) {
		boolean exit = false;
		if(map[x][y].isDeadEnd() && (y==0 || x==xSize-1 || y==ySize-1)) {
			exit = true;
		} else if(map[x][y].isDeadEnd() && startKnown && x==0) {
			exit = true;
		}
		return exit;
	}

	public boolean fieldIsDeadEnd(int x, int y) {
		return map[x][y].isDeadEnd();
	}

	public boolean fieldIsRedPoint(int x, int y) {
		return x==redX && y==redY;
	}

	public void addField(int x, int y, boolean north, boolean east, boolean south, boolean west) {
		map[x][y].setField(north, east, south, west);
		if(!map[x][y-1].isKnown()) {
			if(north) {
				if(y-1==0) map[x][y-1].setDeadEndFound(Direction.SOUTH);
				else map[x][y-1].setPathFound(Direction.SOUTH);
			}
			else map[x][y-1].setEmptyFound(Direction.SOUTH);
		}
		if(!map[x+1][y].isKnown()) {
			if(east) {
				if(x+1==xSize-1) map[x+1][y].setDeadEndFound(Direction.WEST);
				else map[x+1][y].setPathFound(Direction.WEST);
			}
			else map[x+1][y].setEmptyFound(Direction.WEST);
		}
		if(!map[x][y+1].isKnown()) {
			if(south) {
				if(y+1==ySize-1) map[x][y+1].setDeadEndFound(Direction.NORTH);
				else map[x][y+1].setPathFound(Direction.NORTH);
			}
			else map[x][y+1].setEmptyFound(Direction.NORTH);
		}
		if(!map[x-1][y].isKnown()) {
			if(west) {
				if(x-1==0 && startKnown) map[x-1][y].setDeadEndFound(Direction.EAST);
				else map[x-1][y].setPathFound(Direction.EAST);
			}
			else map[x-1][y].setEmptyFound(Direction.EAST);
		}
	}

	public FieldDirectionState getFieldDirectionState(int x, int y, int direction) {
		return map[x][y].getFieldDirectionState(direction);
	}

	public void objectFound(int x, int y, int direction) {
		int xTarget=x;
		int yTarget=y;
		switch(direction) {
			case Direction.NORTH: yTarget--; break;
			case Direction.EAST: xTarget++; break;
			case Direction.SOUTH: yTarget++; break;
			case Direction.WEST: xTarget--; break;
		}
		if(!(xTarget<-1 || yTarget<-1 || xTarget>=xSize || yTarget>=ySize)) {
			map[xTarget][yTarget].setObjectFound((direction+2)%4);
		}
		map[x][y].setObjectFound(direction);
	}

	public void deadEndFound(int x, int y, int direction) {
		for(int i=0; i<4; i++) {
			if(i!=direction) {
				switch(i) {
					case Direction.NORTH: if(hasNeighbor(x, y, i)) map[x][y-1].setEmptyFound((i+2)%4); break;
					case Direction.EAST: if(hasNeighbor(x, y, i)) map[x+1][y].setEmptyFound((i+2)%4); break;
					case Direction.SOUTH: if(hasNeighbor(x, y, i)) map[x][y+1].setEmptyFound((i+2)%4); break;
					case Direction.WEST: if(hasNeighbor(x, y, i)) map[x-1][y].setEmptyFound((i+2)%4); break;
				}
			}
		}
		map[x][y].setDeadEndFound(direction);
	}

	public void redPointFound(int x, int y) {
		redX = x;
		redY = y;
	}

	public int getXSize() {
		return xSize;
	}

	public int getYSize() {
		return ySize;
	}

	public String toString() {
		String result="";
		for(int y=0; y<ySize; y++) {
			for(int x=0; x<xSize; x++) {
				result=result + "X:" + x + " Y:" + y + " " + map[x][y].getFieldDirectionState(Direction.NORTH) + ", "
						+ map[x][y].getFieldDirectionState(Direction.EAST) + ", "
						+ map[x][y].getFieldDirectionState(Direction.SOUTH) + ", "
						+ map[x][y].getFieldDirectionState(Direction.WEST) + "\n";
			}
		}
		return result;
	}

	void switchStartingLine() {
		Field[] temp;
		for(int i=0; i<3; i++) {
			temp=map[i];
			map[i]=map[xSize-3+i];
			map[xSize-3+i]=temp;
		}
	}

	void shrinkX(boolean shrinkFromRight) {
		Field[][] temp=new Field[Config.MINFIELDS][Config.MAXFIELDS];
		if(shrinkFromRight) {
			for(int i=0; i<Config.MINFIELDS; i++) {
				for(int j=0; j<Config.MAXFIELDS; j++) {
					temp[i][j]=map[i][j];
				}
			}
		} else {
			for(int i=Config.MINFIELDS; i>=0; i--) {
				for(int j=0; j<Config.MAXFIELDS; j++) {
					temp[i][j]=map[i][j];
				}
			}
		}
		map=temp;
		xSize=Config.MINFIELDS;
		if(shrinkFromRight) {
			lookForExits(Direction.EAST);
		} else {
			lookForExits(Direction.WEST);
		}
		measuresKnown=true;
	}

	void shrinkY() {
		Field[][] temp=new Field[Config.MAXFIELDS][Config.MINFIELDS];
		for(int i=0; i<Config.MAXFIELDS; i++) {
			for(int j=0; j<Config.MINFIELDS; j++) {
				temp[i][j]=map[i][j];
			}
		}
		map=temp;
		ySize=Config.MINFIELDS;
		lookForExits(Direction.SOUTH);
		measuresKnown=true;
	}

	boolean hasNeighbor(int x, int y, int direction) {
		boolean result=false;
		switch(direction) {
			case Direction.NORTH: if(y-1>=0) result=true; break;
			case Direction.EAST: if(x+1<xSize) result=true; break;
			case Direction.SOUTH: if(y+1<ySize) result=true; break;
			case Direction.WEST: if(x-1>=0) result=true; break;
		}
		return result;
	}

	private void lookForExits(int direction) {
		int nr=0;
		switch(direction) {
			case Direction.WEST: nr=0; break;
			case Direction.EAST: nr=xSize-1; break;
			case Direction.SOUTH: nr=ySize-1; break;
		}
		if(direction==Direction.SOUTH) {
			for(int i=0; i<xSize; i++) {
				if(map[i][nr].getFieldDirectionState((direction+2)%4)==FieldDirectionState.PATH) {
					map[i][nr].setDeadEndFound((direction+2)%4);
				}
			}
		} else {
			for(int i=0; i<ySize; i++) {
				if(map[nr][i].getFieldDirectionState((direction+2)%4)==FieldDirectionState.PATH) {
					map[nr][i].setDeadEndFound((direction+2)%4);
				}
			}
		}
	}

}
